#pragma once

#include <string>
#include <fstream>

// Define a portable debug macro
#if !defined(NDEBUG)
#define DEBUG_MODE
#endif

#ifdef DEBUG_MODE
#define DEBUGCODE(x) x
#else
#define DEBUGCODE(x)
#endif

struct NonCopyable {
	NonCopyable(const NonCopyable &) = delete;
	NonCopyable &operator=(const NonCopyable &) = delete;
	virtual ~NonCopyable();
};

// Auto(func()) allow a function to be called at the end of the scope
template <typename Lambda>
struct ScopeEnd {
	ScopeEnd(Lambda f) : func(f) {}
	~ScopeEnd() { func(); }

private:
	Lambda &func;
};

#define TOKEN_PASTE(x, y) x##y

#define AutoIntern1(lname, aname, ...) \
	auto lname = [&]() { __VA_ARGS__; }; \
	ScopeEnd<decltype(lname)> aname(lname);

#define AutoIntern2(ctr, ...)                                         \
	AutoIntern1(TOKEN_PASTE(AutoFunc, ctr), TOKEN_PASTE(AutoInst, ctr), \
				__VA_ARGS__)
// You should only use this macro
#define AUTO(...) AutoIntern2(__COUNTER__, __VA_ARGS__)

/// The toUpper and toLower function work only on ascii character
char toUpper(char c);
void toUpper(std::string &s);

char toLower(char c);
void toLower(std::string &s);

// Return the file name in a path
std::string getNameInPath(const std::string &path);
std::string getFileType(const std::string &s);
// Return file size in byte
long long getFileSize(const std::string &s);